#!/bin/bash

# ----------------------------------------------------------------------
# Filename:   ftp_local_allow_chroot_list.sh
# Version:    1.0
# Date:       2013/07/29
# Author:     huijing.hei
# Email:      huijing.hei@cs2c.com.cn
# Summary:    02系统基本功能-04网络服务-01vsftp-01字符模式-03本地用户-04允许登录用户访问其他目录
# Notes:       ***
# Copyright:    China Standard Software Co., Ltd.
# History：     
#             Version 1.0, 2013/08/07
#             - Not allow anonymous to login, but allows local users login; 
#	      - allow all local users to chroot other dirs.
# ----------------------------------------------------------------------
##! @TODO:  update vsftpd.conf, and restart vsftpd
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure

function do_setup()
{
    serv=vsftpd
    RHOST=${RHOST}
    VSFTP_CONF="/etc/vsftpd/vsftpd.conf"
    CHROOT_LIST="/etc/vsftpd/chroot_list"

    # anonymous not allowed to login
    TEST_ANON="anonymous"
    TEST_ANON_PASSWD="noone@nowhere.com"

    exists vsftpd ftp expect
    EchoResult "check commands"


    # remote user, need to adduser

    TEST_USER1="ftpuser1"
    TEST_USER1_PASSWD="pass1234"
    TEST_USER2="ftpuser2"
    TEST_USER2_PASSWD="pass1234"

    ${RSH} -n -l root $RHOST "/usr/sbin/userdel -rf $TEST_USER1; /usr/sbin/userdel -rf $TEST_USER2;\
                                    /usr/sbin/useradd $TEST_USER1; /usr/sbin/useradd $TEST_USER2"

    expect -c "
        spawn ssh -l root $RHOST
            expect {
                \"yes/no\" { 
                     send \"yes\r\" 
                     expect \"password: \"
                     send \"$PASSWORD\r\"
                     }

                \"password: \" { 
                     send \"$PASSWORD\r\"
                     expect \"Permission denied\" { send_user \"ssh $RHOST failed\r\"; exit 1; }
                     }
            }

            ### passwd for ftpuser1
            sleep 2
            expect \"# \"
            send \"LANG=C /usr/bin/passwd $TEST_USER1\r\"
            expect {
                \"Unknown user name\" { send_user \"remote useradd $TEST_USER1 failed.\n\"; exit 1; }
                \"ew password: \" { send \"$TEST_USER1_PASSWD\r\" }
            }
            expect \"type new password: \" 
            send \"$TEST_USER1_PASSWD\r\"

           expect {
               \"ew password: \" { send_user \"remote passwd $TEST_USER1 failed.\n\"; exit 1; }
               \"passwd: all authentication tokens updated successfully.\n\" {send_user \"remote passwd $TEST_USER1 success.\n\"}
               }

            ### passwd for ftpuser2
            expect \"# \"
            send \"LANG=C /usr/bin/passwd $TEST_USER2\r\"
            expect {
                \"Unknown user name\" { send_user \"remote useradd $TEST_USER2 failed.\n\"; exit 1; }
                \"ew password: \" { send \"$TEST_USER2_PASSWD\r\" }
            }

            expect \"type new password: \" 
            send \"$TEST_USER2_PASSWD\r\"

           expect {
               \"ew password: \" { send_user \"remote passwd $TEST_USER2 failed.\n\"; exit 1;}
               \"passwd: all authentication tokens updated successfully.\n\" {send_user \"remote passwd $TEST_USER2 success.\n\"}
               }

        expect eof
    "

    # remote, add ftpuser2 to file chroot_list
    ${RSH} -l root -n $RHOST "echo $TEST_USER2 > $CHROOT_LIST"


    # create local tmp file , for upload
    TMP_DIR="/tmp/vsftp$$"
    mkdir -p $TMP_DIR
    EchoResult "mkdir $TMP_DIR"

    echo "test" > $TMP_DIR/upfile

    # remote ftp server, update vsftpd.conf and restart vsftpd
    ${RSH} -l root -n $RHOST "cp $VSFTP_CONF $VSFTP_CONF.bak"
    TMP_VSFTP_CONF="/tmp/vsftpd.conf" 
    cat > ${TMP_VSFTP_CONF} <<-EOF
anonymous_enable=NO

local_enable=YES

write_enable=YES

local_umask=022

dirmessage_enable=YES

xferlog_enable=YES

connect_from_port_20=YES

xferlog_std_format=YES

chroot_local_user=NO
chroot_list_enable=NO
chroot_list_file=/etc/vsftpd/chroot_list

listen=YES

pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
EOF

    ${RCP} $TMP_VSFTP_CONF root@$RHOST:$VSFTP_CONF
    ${RCP} $TMP_VSFTP_CONF root@$RHOST:$VSFTP_CONF
    # restart 
    ${RSH} -l root $RHOST \
       "command -v systemctl && /bin/systemctl restart ${serv}.service || /sbin/service ${serv} restart"

    RE=`${RSH} -l root $RHOST \
       "/bin/netstat -ntlp | grep ${serv}"`
    echo "${RE}" | grep ${serv}
    EchoResult "service ${serv} restart test."

    # upload upfile to server:/var/ftp/ftpdir
    #UP_DIR="ftpdir"
    #${RSH} -l root -n $RHOST "mkdir $UP_DIR; [ -d $UP_DIR ] && chmod 777 $UP_DIR || echo \"$UP_DIR not exits.\""

    trap do_cleanup INT EXIT

}

##! @TODO:  test anonymous not allowed to ftp
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure

function do_anon_ftp()
{
    echo "Test: anonymous not allowed to login"

    expect -c "
        spawn ftp $RHOST
        expect -re \": \"
        send \"$TEST_ANON\r\"
        expect -re \"Password:\"
        send \"$TEST_ANON_PASSWD\r\"

        expect {
          # 530 - Login failed
          \"530\" {send_user \"Login failed as expected; test PASSED\n\"}
          # 230 - Login successful
          \"230\" {send_user \"Login succeeded unexpectedly; test FAILED\n\"; exit 1}
        }

       expect \"ftp> \"
       send \"bye\r\"

       expect eof

       catch wait result
       exit [lindex \$result 3]

    "
}

##! @TODO:  upload and download file, create dir, rename and delete file.
##          allowed all local users to chroot.
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure

function do_test()
{
    echo "Test: allowed local users to upload and download files, can create dir, rename file and delete file.\
                allowed all local users to chroot other dirs."    

    TEST_USER=$1
    TEST_USER_PASSWD=$2

    expect -c "
        spawn ftp $RHOST
        expect -re \": \"
        send \"$TEST_USER\r\"
        expect -re \"Password:\"
        send \"$TEST_USER_PASSWD\r\"

            expect {
                # 530 - Login failed
                \"530\" {send_user \"==> TEST : FAIL (ftp rejected login attempt)\n\";exit 1}
                # login failed
                \"Login failed\" {send_user \"==> TEST : FAIL (ftp rejected login attempt)\n\"; exit 1}
                # 230 - Login successful
                \"230\" {send_user \"==> TEST : PASS (ftp allowed login attempt)\n\"}
            }


       expect \"ftp> \"
       send \"lcd $TMP_DIR\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user put file.\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS local user put file.\n\"}
        }

#       expect \"ftp> \"
#       send \"cd\r\"
#        expect { 
#            # 550 - failed
#            \"550\" { send_user \"==> TEST : FAIL local user put file.\n\n\";exit 1 }
#            # 226 - transfer successful
#            \"226\" {send_user \"==> TEST : PASS local user put file.\n\"}
#        }

       expect \"ftp> \"
       send \"put upfile\r\" 
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user put file.\n\";exit 1 }
            # 553 - failed
            \"553\" { send_user \"==> TEST : FAIL local user put file.\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS local user put file.\n\"}
        }

       expect \"ftp> \"
       send \"mkdir testdir\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user create dir.\n\";exit 1 }
            # 257 - create dir successful
            \"257\" {send_user \"==> TEST : PASS local user create dir.\n\"}
        }
       

       expect \"ftp> \"
       send \"get upfile downfile\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user get file.\n\";exit 1 }
            # 226 - get file
            \"226\" {send_user \"==> TEST : PASS local user get file.\n\"}
        }

       expect \"ftp> \"
       send \"rename upfile upfile.bak\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user rename file.\n\";exit 1 }
            # 250 - rename file
            \"250\" {send_user \"==> TEST : PASS local user rename file.\n\"}
        }

       expect \"ftp> \"
       send \"delete upfile.bak\r\"       
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL local user delete file.\n\";exit 1 }
            # 250 - rename file
            \"250\" {send_user \"==> TEST : PASS local user delete file.\n\"}
        }

       expect \"ftp> \"
       send \"cd /tmp\r\"

     # allow all local user change dirs 
         expect {
            # 550 - change dir, not allowed to change dirs
            \"550\" {send_user \"==> TEST : FAIL deny local user change dirs.\n\"; exit 1 }
            # 250 - change dir
            \"250\" { send_user \"==> TEST : PASS allow local user change dirs.\n\" }
           }

       expect \"ftp> \"
       send \"bye\r\"

       expect eof

       catch wait result
       exit [lindex \$result 3]

    "
}

##! @TODO:  cleanup tmp files, back up vsftpd.conf and restart ftp services.
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure
function do_cleanup()
{
    ${RSH} -l root -n $RHOST "[ -f $VSFTP_CONF.bak ] && mv -f $VSFTP_CONF.bak $VSFTP_CONF; rm -f $CHROOT_LIST"
    ${RSH} -l root -n $RHOST "command -v systemctl && /bin/systemctl stop ${serv}.service || /sbin/service ${serv} stop"
#    ${RSH} -l root -n $RHOST "rm -rf $UP_DIR"
    ${RSH} -l root -n $RHOST "/usr/sbin/userdel -rf $TEST_USER1; /usr/sbin/userdel -rf $TEST_USER2"

    rm -rf $TMP_DIR $TMP_VSFTP_CONF

}
# include lib files

if [ -z "$SFROOT" ]
then
    CMDLIB=./
    SFROOT=./
else
    CMDLIB=${SFROOT}/testcases/Network_Service
fi

. ${SFROOT}/lib/Echo.sh
. ${SFROOT}/lib/XmlParse.sh

. ${CMDLIB}/lib/Net.sh
. ${CMDLIB}/setup.sh

# get RHOST, RUSERNAME, PASSWORD from config.xml
DATA_FILE="${SFROOT}/testcases/Network_Service/config.xml"
[ -e $DATA_FILE ] || { echo "$DATA_FILE not find, test end."; exit 1; }

XmlParse ${DATA_FILE}

GetValue REHOST ReHost
GetValue RUSERNAME UserName
GetValue PASSWORD RootPasswd

export RHOST=${REHOST}
export RUSERNAME=${RUSERNAME}
export PASSWORD=${PASSWORD}


setup_env || { echo "setup env failed, test end."; exit 1; }

do_setup
do_anon_ftp || { echo "test anonymous failed."; exit 1; }
do_test $TEST_USER1 $TEST_USER1_PASSWD || { echo "test local user1 failed."; exit 1; }
do_test $TEST_USER2 $TEST_USER2_PASSWD || { echo "test local user2 failed."; exit 1; }
